﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Telerik.Windows.Documents.Fixed.FormatProviders.Pdf;
using Telerik.Windows.Documents.Fixed.Model;
using Telerik.Windows.Documents.Fixed.Model.ColorSpaces;
using Telerik.Windows.Documents.Fixed.Model.Editing;
using Telerik.Windows.Documents.Fixed.Model.Editing.Tables;
using Telerik.Windows.Documents.Fixed.Model.Objects;
using Telerik.Windows.Documents.Fixed.Model.Resources;
using Telerik.Windows.Documents.Flow.FormatProviders.Html;
using Telerik.Windows.Documents.Flow.Model;
using Telerik.Windows.Documents.Flow.Model.Shapes;

namespace Console_4._7._2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            RadFlowDocument htmlDocument;
            HtmlFormatProvider htmlFormatProvider = new HtmlFormatProvider();

            using (Stream input = File.OpenRead("..\\..\\..\\input.html"))
            {
                htmlDocument = htmlFormatProvider.Import(input, null);
            }

            Telerik.Windows.Documents.Flow.Model.Table htmlTable = htmlDocument.EnumerateChildrenOfType<Telerik.Windows.Documents.Flow.Model.Table>().FirstOrDefault();

            if (htmlTable == null)
            {
                System.Console.WriteLine("No table found in the HTML document.");
                return;
            }

            RadFixedDocument pdfDocument = new RadFixedDocument();

            // Convert HTML table to PDF tables across multiple pages
            ConvertHtmlTableToPdf(htmlTable, pdfDocument);

            // Save the PDF document
            PdfFormatProvider pdfProvider = new PdfFormatProvider();
            using (Stream output = File.Create("output.pdf"))
            {
                pdfProvider.Export(pdfDocument, output);
            }

            var psi = new ProcessStartInfo()
            {
                FileName = "output.pdf",
                UseShellExecute = true
            };
            Process.Start(psi);



        }

        // Store images with their positions for rendering after table is drawn
        private static List<ImageInfo> pendingImages = new List<ImageInfo>();

        private class ImageInfo
        {
            public Telerik.Windows.Documents.Fixed.Model.Resources.ImageSource ImageSource { get; set; }
            public double X { get; set; }
            public double Y { get; set; }
            public double Width { get; set; }
            public double Height { get; set; }
            public int RowIndex { get; set; }
            public int CellIndex { get; set; }
        }

        static void ConvertHtmlTableToPdf(Telerik.Windows.Documents.Flow.Model.Table htmlTable, RadFixedDocument pdfDocument)
        {
            const double pageMargin = 72; // 1 inch margin
            const double maxTableWidth = 595.2 - (2 * pageMargin); // A4 width minus margins
            const double maxTableHeight = 841.8 - (2 * pageMargin); // A4 height minus margins

            RadFixedPage currentPage = pdfDocument.Pages.AddPage();
            FixedContentEditor currentEditor = new FixedContentEditor(currentPage);

            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table currentPdfTable = new Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table();
            double currentTableHeight = 0;
            pendingImages.Clear(); // Reset pending images for new table

            // Get all rows from the HTML table
            var htmlRows = htmlTable.Rows.ToList();
            int columnCount = htmlRows.Count > 0 ? htmlRows[0].Cells.Count : 0;

            for (int rowIndex = 0; rowIndex < htmlRows.Count; rowIndex++)
            {
                var htmlRow = htmlRows[rowIndex];

                // Calculate estimated row height BEFORE adding it to the table
                double estimatedRowHeight = CalculateEstimatedRowHeightFromHtmlRow(htmlRow, maxTableWidth / columnCount);
                double projectedTableHeight = currentTableHeight + estimatedRowHeight;

                // Check if adding this row would exceed page height
                if (projectedTableHeight > maxTableHeight && currentPdfTable.Rows.Count > 0)
                {
                    // Draw the current table on the page (without the current row)
                    DrawTableOnPage(currentEditor, currentPdfTable, pageMargin);
                    
                    // Draw any pending images for this table
                    DrawPendingImages(currentEditor, pageMargin);

                    // Create a new page and table
                    currentPage = pdfDocument.Pages.AddPage();
                    currentEditor = new FixedContentEditor(currentPage);
                    currentPdfTable = new Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table();
                    currentTableHeight = 0;
                    pendingImages.Clear(); // Reset for new page
                }

                // Now add the current row to the table (either current or new)
                var pdfRow = currentPdfTable.Rows.AddTableRow();

                // Copy cells from HTML row to PDF row
                for (int cellIndex = 0; cellIndex < htmlRow.Cells.Count; cellIndex++)
                {
                    var htmlCell = htmlRow.Cells[cellIndex];
                    var pdfCell = pdfRow.Cells.AddTableCell();

                    // Copy cell content including images
                    CopyCellContentToPdf(htmlCell, pdfCell, maxTableWidth / columnCount, rowIndex, cellIndex);

                    // Set cell properties with basic padding
                    var cellBorder = new Border(1, new RgbColor(0, 0, 0));
                    pdfCell.Borders = new TableCellBorders(cellBorder, cellBorder, cellBorder, cellBorder);
                    pdfCell.PreferredWidth = maxTableWidth / columnCount;
                }

                // Update the current table height
                currentTableHeight += estimatedRowHeight;
            }

            // Draw the final table if it has rows
            if (currentPdfTable.Rows.Count > 0)
            {
                DrawTableOnPage(currentEditor, currentPdfTable, pageMargin);
                DrawPendingImages(currentEditor, pageMargin);
            }
        }

        static void CopyCellContentToPdf(Telerik.Windows.Documents.Flow.Model.TableCell htmlCell,
            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.TableCell pdfCell,
            double cellWidth, int rowIndex, int cellIndex)
        {
            foreach (var block in htmlCell.Blocks)
            {
                if (block is Paragraph paragraph)
                {
                    Block newParagraph = new Block();
                    bool hasContent = false;

                    foreach (var inline in paragraph.Inlines)
                    {
                        if (inline is Run run)
                        {
                            if (!string.IsNullOrEmpty(run.Text))
                            {
                                newParagraph.InsertText(run.Text);
                                hasContent = true;
                            }
                        }
                        else if (inline is ImageInline imageInline)
                        {
                            try
                            {
                                // For now, replace images with descriptive text
                                // This is more reliable than complex image positioning
                                string imageInfo = GetImageInfo(imageInline);
                                newParagraph.InsertText($"[IMAGE: {imageInfo}]");
                                hasContent = true;
                                
                                System.Console.WriteLine($"Image found in row {rowIndex}, cell {cellIndex}: {imageInfo}");
                            }
                            catch (Exception ex)
                            {
                                newParagraph.InsertText("[Image Error]");
                                hasContent = true;
                                System.Console.WriteLine($"Failed to process image: {ex.Message}");
                            }
                        }
                    }

                    if (hasContent)
                    {
                        pdfCell.Blocks.Add(newParagraph);
                    }
                }
            }
        }

        static string GetImageInfo(ImageInline imageInline)
        {
            try
            {
                double width = imageInline.Image.Width;
                double height = imageInline.Image.Height;
                string extension = imageInline.Image.ImageSource.Extension ?? "unknown";
                int dataSize = imageInline.Image.ImageSource.Data?.Length ?? 0;
                
                return $"{width}x{height} {extension.ToUpper()} ({dataSize} bytes)";
            }
            catch
            {
                return "Unknown dimensions";
            }
        }

        static void DrawPendingImages(FixedContentEditor editor, double margin)
        {
            // This is a simplified approach - in a real implementation, you would need to 
            // calculate the exact positions of cells and place images accordingly
            // For now, we'll skip the complex positioning and just acknowledge the images exist
            
            if (pendingImages.Count > 0)
            {
                System.Console.WriteLine($"Note: {pendingImages.Count} images were found but not rendered due to PDF table cell limitations.");
                // In a production implementation, you would:
                // 1. Calculate exact cell positions after table is drawn
                // 2. Use editor.DrawImage() to position images at calculated coordinates
                // 3. This requires complex coordinate calculations based on table layout
            }
        }

        static double CalculateEstimatedRowHeightFromHtmlRow(Telerik.Windows.Documents.Flow.Model.TableRow htmlRow, double cellWidth)
        {
            // Calculate estimated row height from HTML row before converting to PDF
            double baseRowHeight = 25; // Base height for a row
            double maxCellHeight = baseRowHeight;

            foreach (var htmlCell in htmlRow.Cells)
            {
                double cellHeight = baseRowHeight;

                // Add height for each block of content
                foreach (var block in htmlCell.Blocks)
                {
                    if (block is Paragraph paragraph)
                    {
                        // Count lines of text and images
                        int textLength = 0;
                        double maxImageHeight = 0;

                        foreach (var inline in paragraph.Inlines)
                        {
                            if (inline is Run run)
                            {
                                textLength += run.Text.Length;
                            }
                            else if (inline is ImageInline imageInline)
                            {
                                try
                                {
                                    double imageHeight = imageInline.Image.Height;
                                    double imageWidth = imageInline.Image.Width;

                                    // Scale image height if width needs to be scaled to fit cell
                                    if (imageWidth > cellWidth - 10)
                                    {
                                        double scale = (cellWidth - 10) / imageWidth;
                                        imageHeight *= scale;
                                    }

                                    maxImageHeight = Math.Max(maxImageHeight, imageHeight);
                                }
                                catch
                                {
                                    // Default image height if we can't read the actual dimensions
                                    maxImageHeight = Math.Max(maxImageHeight, 50);
                                }
                            }
                        }

                        // Estimate lines based on character count (assuming ~50 chars per line)
                        int estimatedLines = Math.Max(1, textLength / 50);
                        double textHeight = (estimatedLines - 1) * 15;

                        // Use the larger of text height or image height
                        cellHeight += Math.Max(textHeight, maxImageHeight);
                    }
                    else
                    {
                        cellHeight += 15; // Approximate height per non-paragraph block
                    }
                }

                if (cellHeight > maxCellHeight)
                {
                    maxCellHeight = cellHeight;
                }
            }

            return maxCellHeight;
        }

        static void DrawTableOnPage(FixedContentEditor editor, Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table table, double margin)
        {
            // Set table position
            editor.Position.Translate(margin, margin);

            // Draw the table
            editor.DrawTable(table);
        }
    }
}
